home *** CD-ROM | disk | FTP | other *** search
/ Supercompiler 1997 / SUPERCOMPILER97.iso / Delphi 3.0 / DATA.Z / mplayer.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-01-29  |  45.1 KB  |  1,571 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Delphi Visual Component Library                 }
  5. {                                                       }
  6. {       Copyright (c) 1995,97 Borland International     }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit MPlayer;
  11.  
  12. {$R-}
  13.  
  14. interface
  15.  
  16. uses Windows, Classes, Controls, Forms, Graphics, Messages,
  17.   MMSystem, Dialogs, SysUtils;
  18.  
  19. type
  20.   TMPBtnType = (btPlay, btPause, btStop, btNext, btPrev, btStep, btBack,
  21.     btRecord, btEject);
  22.   TButtonSet = set of TMPBtnType;
  23.  
  24.   TMPGlyph = (mgEnabled, mgDisabled, mgColored);
  25.   TMPButton = record
  26.     Visible: Boolean;
  27.     Enabled: Boolean;
  28.     Colored: Boolean;
  29.     Auto: Boolean;
  30.     Bitmaps: array[TMPGlyph] of TBitmap;
  31.   end;
  32.  
  33.   TMPDeviceTypes = (dtAutoSelect, dtAVIVideo, dtCDAudio, dtDAT, dtDigitalVideo, dtMMMovie,
  34.     dtOther, dtOverlay, dtScanner, dtSequencer, dtVCR, dtVideodisc, dtWaveAudio);
  35.   TMPTimeFormats = (tfMilliseconds, tfHMS, tfMSF, tfFrames, tfSMPTE24, tfSMPTE25,
  36.     tfSMPTE30, tfSMPTE30Drop, tfBytes, tfSamples, tfTMSF);
  37.   TMPModes = (mpNotReady, mpStopped, mpPlaying, mpRecording, mpSeeking,
  38.     mpPaused, mpOpen);
  39.   TMPNotifyValues = (nvSuccessful, nvSuperseded, nvAborted, nvFailure);
  40.     
  41.   TMPDevCaps = (mpCanStep, mpCanEject, mpCanPlay, mpCanRecord, mpUsesWindow);
  42.   TMPDevCapsSet = set of TMPDevCaps;
  43.   
  44.   EMPNotify = procedure (Sender: TObject; Button: TMPBtnType;
  45.     var DoDefault: Boolean) of object;
  46.   EMPPostNotify = procedure (Sender: TObject; Button: TMPBtnType) of object;
  47.  
  48.   EMCIDeviceError = class(Exception);
  49.   
  50.   TMediaPlayer = class(TCustomControl)
  51.   private
  52.     Buttons: array[TMPBtnType] of TMPButton;
  53.     FVisibleButtons: TButtonSet;
  54.     FEnabledButtons: TButtonSet;
  55.     FColoredButtons: TButtonSet;
  56.     FAutoButtons: TButtonSet;
  57.     Pressed: Boolean;
  58.     Down: Boolean;
  59.     CurrentButton: TMPBtnType;
  60.     CurrentRect: TRect;
  61.     ButtonWidth: Integer;
  62.     MinBtnSize: TPoint;
  63.     FOnClick: EMPNotify;
  64.     FOnPostClick: EMPPostNotify;
  65.     FOnNotify: TNotifyEvent;
  66.     FocusedButton: TMPBtnType;
  67.     MCIOpened: Boolean;
  68.     FCapabilities: TMPDevCapsSet;
  69.     FCanPlay: Boolean;
  70.     FCanStep: Boolean;
  71.     FCanEject: Boolean;
  72.     FCanRecord: Boolean;
  73.     FHasVideo: Boolean;
  74.     FFlags: Longint;
  75.     FWait: Boolean;
  76.     FNotify: Boolean;
  77.     FUseWait: Boolean;
  78.     FUseNotify: Boolean;
  79.     FUseFrom: Boolean;
  80.     FUseTo: Boolean;
  81.     FDeviceID: Word;
  82.     FDeviceType: TMPDeviceTypes;
  83.     FTo: Longint;
  84.     FFrom: Longint;
  85.     FFrames: Longint;
  86.     FError: Longint;
  87.     FNotifyValue: TMPNotifyValues;
  88.     FDisplay: TWinControl;
  89.     FDWidth: Integer;
  90.     FDHeight: Integer;
  91.     FElementName: string;
  92.     FAutoEnable: Boolean;
  93.     FAutoOpen: Boolean;
  94.     FAutoRewind: Boolean;
  95.     FShareable: Boolean;
  96.  
  97.     procedure LoadBitmaps;
  98.     procedure DestroyBitmaps;
  99.     procedure SetEnabledButtons(Value: TButtonSet);
  100.     procedure SetColored(Value: TButtonSet);
  101.     procedure SetVisible(Value: TButtonSet);
  102.     procedure SetAutoEnable(Value: Boolean);
  103.     procedure DrawAutoButtons;
  104.     procedure DoMouseDown(XPos, YPos: Integer);
  105.     procedure WMLButtonDown(var Message: TWMLButtonDown);
  106.       message WM_LButtonDown;
  107.     procedure WMLButtonDblClk(var Message: TWMLButtonDblClk);
  108.       message WM_LButtonDblClk;
  109.     procedure WMMouseMove(var Message: TWMMouseMove);
  110.       message WM_MouseMove;
  111.     procedure WMLButtonUp(var Message: TWMLButtonUp);
  112.       message WM_LButtonUp;
  113.     procedure WMSetFocus(var Message: TWMSetFocus);
  114.       message WM_SETFOCUS;
  115.     procedure WMKillFocus(var Message: TWMKillFocus);
  116.       message WM_KILLFOCUS;
  117.     procedure WMGetDlgCode(var Message: TWMGetDlgCode);
  118.       message WM_GETDLGCODE;
  119.     procedure WMSize(var Message: TWMSize);
  120.       message WM_SIZE;
  121.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  122.     function VisibleButtonCount: Integer;
  123.     procedure Adjust;
  124.     procedure DoClick(Button: TMPBtnType);
  125.     procedure DoPostClick(Button: TMPBtnType);
  126.     procedure DrawButton(Btn: TMPBtnType; X: Integer);
  127.     procedure CheckIfOpen;
  128.     procedure SetPosition(Value: Longint);
  129.     procedure SetDeviceType( Value: TMPDeviceTypes );
  130.     procedure SetWait( Flag: Boolean );
  131.     procedure SetNotify( Flag: Boolean );
  132.     procedure SetFrom( Value: Longint );
  133.     procedure SetTo( Value: Longint );
  134.     procedure SetTimeFormat( Value: TMPTimeFormats );
  135.     procedure SetDisplay( Value: TWinControl );
  136.     procedure SetOrigDisplay;
  137.     procedure SetDisplayRect( Value: TRect );
  138.     function GetDisplayRect: TRect;
  139.     procedure GetDeviceCaps;
  140.     function GetStart: Longint;
  141.     function GetLength: Longint;
  142.     function GetMode: TMPModes;
  143.     function GetTracks: Longint;
  144.     function GetPosition: Longint;
  145.     function GetErrorMessage: string;
  146.     function GetTimeFormat: TMPTimeFormats;
  147.     function GetTrackLength(TrackNum: Integer): Longint;
  148.     function GetTrackPosition(TrackNum: Integer): Longint;
  149.   protected
  150.     procedure Loaded; override;
  151.     procedure AutoButtonSet(Btn: TMPBtnType); dynamic;
  152.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  153.     procedure Paint; override;
  154.     procedure MMNotify(var Message: TMessage); message MM_MCINOTIFY;
  155.     procedure Click(Button: TMPBtnType; var DoDefault: Boolean); dynamic;
  156.     procedure PostClick(Button: TMPBtnType); dynamic;
  157.     procedure DoNotify; dynamic;
  158.     procedure Updated; override;
  159.   public
  160.     constructor Create(AOwner: TComponent); override;
  161.     destructor Destroy; override;
  162.     procedure Open;
  163.     procedure Close;
  164.     procedure Play;
  165.     procedure Stop;
  166.     procedure Pause; {Pause & Resume/Play}
  167.     procedure Step;
  168.     procedure Back;
  169.     procedure Previous;
  170.     procedure Next;
  171.     procedure StartRecording;
  172.     procedure Eject;
  173.     procedure Save;
  174.     procedure PauseOnly;
  175.     procedure Resume;
  176.     procedure Rewind;
  177.     property TrackLength[TrackNum: Integer]: Longint read GetTrackLength;
  178.     property TrackPosition[TrackNum: Integer]: Longint read GetTrackPosition;
  179.     property Capabilities: TMPDevCapsSet read FCapabilities;
  180.     property Error: Longint read FError;
  181.     property ErrorMessage: string read GetErrorMessage;
  182.     property Start: Longint read GetStart;
  183.     property Length: Longint read GetLength;
  184.     property Tracks: Longint read GetTracks;
  185.     property Frames: Longint read FFrames write FFrames;
  186.     property Mode: TMPModes read GetMode;
  187.     property Position: Longint read GetPosition write SetPosition;
  188.     property Wait: Boolean read FWait write SetWait;
  189.     property Notify: Boolean read FNotify write SetNotify;
  190.     property NotifyValue: TMPNotifyValues read FNotifyValue;
  191.     property StartPos: Longint read FFrom write SetFrom;
  192.     property EndPos: Longint read FTo write SetTo;
  193.     property DeviceID: Word read FDeviceID;
  194.     property TimeFormat: TMPTimeFormats read GetTimeFormat write SetTimeFormat;
  195.     property DisplayRect: TRect read GetDisplayRect write SetDisplayRect;
  196.   published
  197.     property ColoredButtons: TButtonSet read FColoredButtons write SetColored
  198.        default [btPlay, btPause, btStop, btNext, btPrev, btStep, btBack,
  199.       btRecord, btEject];
  200.     property Enabled;
  201.     property EnabledButtons: TButtonSet read FEnabledButtons write SetEnabledButtons
  202.        default [btPlay, btPause, btStop, btNext, btPrev, btStep, btBack,
  203.       btRecord, btEject];
  204.     property VisibleButtons: TButtonSet read FVisibleButtons write SetVisible
  205.        default [btPlay, btPause, btStop, btNext, btPrev, btStep, btBack,
  206.       btRecord, btEject];
  207.     property AutoEnable: Boolean read FAutoEnable write SetAutoEnable default True;
  208.     property AutoOpen: Boolean read FAutoOpen write FAutoOpen default False;
  209.     property AutoRewind: Boolean read FAutoRewind write FAutoRewind default True;
  210.     property DeviceType: TMPDeviceTypes read FDeviceType write SetDeviceType default dtAutoSelect;
  211.     property Display: TWinControl read FDisplay write SetDisplay;
  212.     property FileName: string read FElementName write FElementName;
  213.     property Shareable: Boolean read FShareable write FShareable default False;
  214.     property Visible;
  215.     property ParentShowHint;
  216.     property ShowHint;
  217.     property PopupMenu;
  218.     property TabOrder;
  219.     property TabStop default True;
  220.     property OnClick: EMPNotify read FOnClick write FOnClick;
  221.     property OnEnter;
  222.     property OnExit;
  223.     property OnPostClick: EMPPostNotify read FOnPostClick write FOnPostClick;
  224.     property OnNotify: TNotifyEvent read FOnNotify write FOnNotify;
  225.   end;
  226.  
  227. implementation
  228.  
  229. uses Consts;
  230.  
  231. {$R MPLAYER}
  232.  
  233. const
  234.   mci_Back     = $0899;  { mci_Step reverse }
  235.  
  236.   BtnStateName: array[TMPGlyph] of PChar = ('EN', 'DI', 'CL');
  237.   BtnTypeName: array[TMPBtnType] of PChar = ('MPPLAY', 'MPPAUSE', 'MPSTOP',
  238.     'MPNEXT', 'MPPREV', 'MPSTEP', 'MPBACK', 'MPRECORD', 'MPEJECT');
  239.  
  240. constructor TMediaPlayer.Create(AOwner: TComponent);
  241. var
  242.   I: TMPBtnType;
  243. begin
  244.   inherited Create(AOwner);
  245.   ControlStyle := ControlStyle + [csOpaque];
  246.   LoadBitmaps;
  247.   FVisibleButtons := [btPlay, btPause, btStop, btNext, btPrev, btStep,
  248.     btBack, btRecord, btEject];
  249.   FEnabledButtons := [btPlay, btPause, btStop, btNext, btPrev, btStep,
  250.     btBack, btRecord, btEject];
  251.   FColoredButtons := [btPlay, btPause, btStop, btNext, btPrev, btStep,
  252.     btBack, btRecord, btEject];
  253.   for I := Low(Buttons) to High(Buttons) do
  254.   begin
  255.     Buttons[I].Visible := True;
  256.     Buttons[I].Enabled := True;
  257.     Buttons[I].Colored := True;
  258.     Buttons[I].Auto := False; {enabled/disabled dynamically}
  259.   end;
  260.   Width := 240;
  261.   Height := 30;
  262.   FocusedButton := btPlay;
  263.   FAutoEnable := True;
  264.   FAutoOpen := False;
  265.   FAutoRewind := True;
  266.   FDeviceType := dtAutoSelect; {select through file name extension}
  267. end;
  268.  
  269. destructor TMediaPlayer.Destroy;
  270. var
  271.   GenParm: TMCI_Generic_Parms;
  272. begin
  273.   if FDeviceID <> 0 then
  274.     mciSendCommand( FDeviceID, mci_Close, mci_Wait, Longint(@GenParm));
  275.   DestroyBitmaps;
  276.   inherited Destroy;
  277. end;
  278.  
  279. procedure TMediaPlayer.Loaded;
  280. begin
  281.   inherited Loaded;
  282.   if (not (csDesigning in ComponentState)) and FAutoOpen then
  283.     Open;
  284. end;
  285.  
  286. procedure TMediaPlayer.LoadBitmaps;
  287. var
  288.   I: TMPBtnType;
  289.   J: TMPGlyph;
  290.   ResName: array[0..40] of Char;
  291. begin
  292.   MinBtnSize := Point(0, 0);
  293.   for I := Low(Buttons) to High(Buttons) do
  294.   begin
  295.     for J := Low(TMPGlyph) to High(TMPGlyph) do
  296.     begin
  297.       Buttons[I].Bitmaps[J] := TBitmap.Create;
  298.       Buttons[I].Bitmaps[J].Handle := LoadBitmap(HInstance,
  299.         StrFmt(ResName, '%s_%s', [BtnStateName[J], BtnTypeName[I]]));
  300.       if MinBtnSize.X < Buttons[I].Bitmaps[J].Width then
  301.         MinBtnSize.X := Buttons[I].Bitmaps[J].Width;
  302.       if MinBtnSize.Y < Buttons[I].Bitmaps[J].Height then
  303.         MinBtnSize.Y := Buttons[I].Bitmaps[J].Height;
  304.     end;
  305.   end;
  306.   Inc(MinBtnSize.X, 2 * 4);
  307.   Inc(MinBtnSize.Y, 2 * 2);
  308. end;
  309.  
  310. procedure TMediaPlayer.DestroyBitmaps;
  311. var
  312.   I: TMPBtnType;
  313.   J: TMPGlyph;
  314. begin
  315.   for I := Low(Buttons) to High(Buttons) do
  316.     for J := Low(TMPGlyph) to High(TMPGlyph) do
  317.       Buttons[I].Bitmaps[J].Free;
  318. end;
  319.  
  320.  
  321. procedure TMediaPlayer.SetAutoEnable(Value: Boolean);
  322. begin
  323.   if Value <> FAutoEnable then
  324.   begin
  325.     FAutoEnable := Value;
  326.     if FAutoEnable then
  327.       DrawAutoButtons  {paint buttons based on current state of device}
  328.     else
  329.       SetEnabledButtons(FEnabledButtons);  {paint buttons based on Enabled}
  330.   end;
  331. end;
  332.  
  333. procedure TMediaPlayer.SetEnabledButtons(Value: TButtonSet);
  334. var
  335.   I: TMPBtnType;
  336. begin
  337.   FEnabledButtons := Value;
  338.   for I := Low(Buttons) to High(Buttons) do
  339.     Buttons[I].Enabled := I in FEnabledButtons;
  340.   Invalidate;
  341. end;
  342.  
  343. procedure TMediaPlayer.DrawAutoButtons;
  344. var
  345.   I: TMPBtnType;
  346. begin
  347.   for I := Low(Buttons) to High(Buttons) do
  348.     Buttons[I].Auto := I in FAutoButtons;
  349.   Invalidate;
  350. end;
  351.  
  352. procedure TMediaPlayer.SetColored(Value: TButtonSet);
  353. var
  354.   I: TMPBtnType;
  355. begin
  356.   FColoredButtons := Value;
  357.   for I := Low(Buttons) to High(Buttons) do
  358.     Buttons[I].Colored := I in FColoredButtons;
  359.   Invalidate;
  360. end;
  361.  
  362. procedure TMediaPlayer.SetVisible(Value: TButtonSet);
  363. var
  364.   I: TMPBtnType;
  365. begin
  366.   FVisibleButtons := Value;
  367.   for I := Low(Buttons) to High(Buttons) do
  368.     Buttons[I].Visible := I in FVisibleButtons;
  369.   if csUpdating in ComponentState then
  370.   begin
  371.     ButtonWidth := ((Width - 1) div VisibleButtonCount) + 1;
  372.     Invalidate;
  373.   end
  374.   else Adjust;
  375. end;
  376.  
  377. function TMediaPlayer.VisibleButtonCount: Integer;
  378. var
  379.   I: TMPBtnType;
  380. begin
  381.   Result := 0;
  382.   for I := Low(Buttons) to High(Buttons) do
  383.     if Buttons[I].Visible then Inc(Result);
  384.   if Result = 0 then Inc(Result);
  385. end;
  386.  
  387. procedure TMediaPlayer.Adjust;
  388. var
  389.   Count: Integer;
  390. begin
  391.   Count := VisibleButtonCount;
  392.   Width := Count * (ButtonWidth - 1) + 1;
  393.   Invalidate;
  394. end;
  395.  
  396. procedure TMediaPlayer.WMSize(var Message: TWMSize);
  397. var
  398.   Count: Integer;
  399.   MinSize: TPoint;
  400.   W, H: Integer;
  401. begin
  402.   inherited;
  403.   if not (csUpdating in ComponentState) then
  404.   begin
  405.     { check for minimum size }
  406.     Count := VisibleButtonCount;
  407.     MinSize.X := Count * (MinBtnSize.X - 1) + 1;
  408.     MinSize.Y := MinBtnSize.Y;
  409.     ButtonWidth := ((Width - 1) div Count) + 1;
  410.  
  411.     W := Count * (ButtonWidth - 1) + 1;
  412.     if W < MinSize.X then W := MinSize.X;
  413.     if Height < MinSize.Y then H := MinSize.Y
  414.     else H := Height;
  415.  
  416.     if (W <> Width) or (H <> Height) then
  417.       SetBounds(Left, Top, W, H);
  418.  
  419.     Message.Result := 0;
  420.   end;
  421. end;
  422.  
  423. procedure TMediaPlayer.DrawButton(Btn: TMPBtnType; X: Integer);
  424. var
  425.   IsDown: Boolean;
  426.   BX, BY: Integer;
  427.   TheGlyph: TMPGlyph;
  428.   Bitmap: TBitmap;
  429.   R: TRect;
  430. begin
  431.   IsDown := Down and (Btn = CurrentButton);
  432.   with Canvas do
  433.   begin
  434.     Brush.Style := bsSolid;
  435.     Brush.Color := clBtnFace;
  436.     Pen.Color := clWindowFrame;
  437.     Pen.Width := 1;
  438.     Rectangle(X, 0, X + ButtonWidth, Height);
  439.  
  440.     { draw button beveling }
  441.     if IsDown then
  442.     begin
  443.       Pen.Color := clBtnShadow;
  444.       MoveTo(X + 1, Height - 2);
  445.       LineTo(X + 1, 1);
  446.       LineTo(X + ButtonWidth - 1, 1);
  447.     end
  448.     else
  449.     begin
  450.       Pen.Color := clBtnHighlight;
  451.       MoveTo(X + 1, Height - 2);
  452.       LineTo(X + 1, 1);
  453.       LineTo(X + ButtonWidth - 1, 1);
  454.       Pen.Color := clBtnShadow;
  455.       MoveTo(X + 2, Height - 2);
  456.       LineTo(X + ButtonWidth - 2, Height - 2);
  457.       LineTo(X + ButtonWidth - 2, 1);
  458.     end;
  459.  
  460.     {which bitmap logic - based on Enabled, Colored, and AutoEnable}
  461.     if Enabled or (csDesigning in ComponentState) then
  462.     begin  {Enabled only affects buttons at runtime}
  463.       if FAutoEnable and not (csDesigning in ComponentState) then
  464.       begin  {AutoEnable only affects buttons at runtime}
  465.         if Buttons[Btn].Auto then {is button available, based on device state}
  466.         begin
  467.           TheGlyph := mgEnabled;
  468.           if Buttons[Btn].Colored then
  469.             TheGlyph := mgColored;
  470.         end
  471.         else TheGlyph := mgDisabled;  {button is not available}
  472.       end
  473.       else  {when not AutoEnabled or at design-time, check Enabled}
  474.       begin
  475.         if Buttons[Btn].Enabled then
  476.         begin
  477.           TheGlyph := mgEnabled;
  478.           if Buttons[Btn].Colored then
  479.             TheGlyph := mgColored;
  480.         end
  481.         else TheGlyph := mgDisabled;
  482.       end;
  483.     end
  484.     else TheGlyph := mgDisabled; {main switch set to disabled}
  485.  
  486.     Bitmap := Buttons[Btn].Bitmaps[TheGlyph];
  487.     BX := (ButtonWidth div 2) - (Bitmap.Width div 2);
  488.     BY := (Height div 2) - (Bitmap.Height div 2);
  489.     if IsDown then
  490.     begin
  491.       Inc(BX);
  492.       Inc(BY);
  493.     end;
  494.     BrushCopy(Bounds(X + BX, BY, Bitmap.Width, Bitmap.Height),
  495.       Bitmap, Rect(0, 0, Bitmap.Width, Bitmap.Height), clOlive);
  496.   end;
  497.  
  498.   if (GetFocus = Handle) and (Btn = FocusedButton) then
  499.   begin
  500.     R := Bounds(X, 0, ButtonWidth, Height);
  501.     InflateRect(R, -3, -3);
  502.     if IsDown then OffsetRect(R, 1, 1);
  503.     DrawFocusRect(Canvas.Handle, R);
  504.   end;
  505. end;
  506.  
  507. procedure TMediaPlayer.Paint;
  508. var
  509.   X: Integer;
  510.   I: TMPBtnType;
  511. begin
  512.   with Canvas do
  513.   begin
  514.     Brush.Style := bsClear;
  515.     Pen.Color := clWindowFrame;
  516.     Pen.Width := 1;
  517.     Rectangle(0, 0, Width, Height);
  518.  
  519.     X := 0;
  520.     for I := Low(Buttons) to High(Buttons) do
  521.     begin
  522.       if Buttons[I].Visible then
  523.       begin
  524.         DrawButton(I, X);
  525.         Inc(X, ButtonWidth - 1);
  526.       end;
  527.     end;
  528.   end;
  529. end;
  530.  
  531. {AutoEnable=True, enable/disable button set based on button passed (pressed)}
  532. procedure TMediaPlayer.AutoButtonSet(Btn: TMPBtnType);
  533. begin
  534.   case Btn of
  535.     btPlay:
  536.     begin
  537.       FAutoButtons := FAutoButtons - [btPlay,btRecord];
  538.       FAutoButtons := FAutoButtons + [btStop,btPause];
  539.     end;
  540.     btPause:
  541.     begin
  542.       if FCanPlay then Include(FAutoButtons,btPlay);
  543.       if FCanRecord then Include(FAutoButtons,btRecord);
  544.     end;
  545.     btStop:
  546.     begin
  547.       if FCanPlay then Include(FAutoButtons,btPlay);
  548.       if FCanRecord then Include(FAutoButtons,btRecord);
  549.       FAutoButtons := FAutoButtons - [btStop,btPause];
  550.     end;
  551.     btNext:
  552.     begin
  553.       if FCanPlay then Include(FAutoButtons,btPlay);
  554.       if FCanRecord then Include(FAutoButtons,btRecord);
  555.       FAutoButtons := FAutoButtons - [btStop,btPause];
  556.     end;
  557.     btPrev:
  558.     begin
  559.       if FCanPlay then Include(FAutoButtons,btPlay);
  560.       if FCanRecord then Include(FAutoButtons,btRecord);
  561.       FAutoButtons := FAutoButtons - [btStop,btPause];
  562.     end;
  563.     btStep:
  564.     begin
  565.       if FCanPlay then Include(FAutoButtons,btPlay);
  566.       if FCanRecord then Include(FAutoButtons,btRecord);
  567.       FAutoButtons := FAutoButtons - [btStop,btPause];
  568.     end;
  569.     btBack:
  570.     begin
  571.       if FCanPlay then Include(FAutoButtons,btPlay);
  572.       if FCanRecord then Include(FAutoButtons,btRecord);
  573.       FAutoButtons := FAutoButtons - [btStop,btPause];
  574.     end;
  575.     btRecord:
  576.     begin
  577.       FAutoButtons := FAutoButtons - [btPlay,btRecord];
  578.       FAutoButtons := FAutoButtons + [btStop,btPause];
  579.     end;
  580.     btEject: {without polling no way to determine when CD is inserted}
  581.     begin
  582.       if FCanPlay then Include(FAutoButtons,btPlay);
  583.       if FCanRecord then Include(FAutoButtons,btRecord);
  584.       FAutoButtons := FAutoButtons - [btStop,btPause];
  585.     end;
  586.   end;
  587. end;
  588.       
  589. procedure TMediaPlayer.DoMouseDown(XPos, YPos: Integer);
  590. var
  591.   I: TMPBtnType;
  592.   X: Integer;
  593. begin
  594.   {which button was clicked}
  595.   X := 0;
  596.   for I := Low(Buttons) to High(Buttons) do
  597.   begin
  598.     if Buttons[I].Visible then
  599.     begin
  600.       if (XPos >= X) and (XPos <= X + ButtonWidth) then
  601.       begin
  602.         if FAutoEnable then
  603.           if Buttons[I].Auto then Break
  604.           else Exit;
  605.         if Buttons[I].Enabled then Break
  606.         else Exit;
  607.       end;
  608.       Inc(X, ButtonWidth - 1);
  609.     end;
  610.   end;
  611.   CurrentButton := I;
  612.   if CurrentButton <> FocusedButton then
  613.   begin
  614.     FocusedButton := CurrentButton;
  615.     Paint;
  616.   end;
  617.   CurrentRect := Rect(X, 0, X + ButtonWidth, Height);
  618.   Pressed := True;
  619.   Down := True;
  620.   DrawButton(I, X);
  621.   MouseCapture := True;
  622. end;
  623.  
  624. procedure TMediaPlayer.WMLButtonDown(var Message: TWMLButtonDown);
  625. begin
  626.   DoMouseDown(Message.XPos, Message.YPos);
  627. end;
  628.  
  629. procedure TMediaPlayer.WMLButtonDblClk(var Message: TWMLButtonDblClk);
  630. begin
  631.   DoMouseDown(Message.XPos, Message.YPos);
  632. end;
  633.  
  634. procedure TMediaPlayer.WMMouseMove(var Message: TWMMouseMove);
  635. var
  636.   P: TPoint;
  637. begin
  638.   if Pressed then
  639.   begin
  640.     P := Point(Message.XPos, Message.YPos);
  641.     if PtInRect(CurrentRect, P) <> Down then
  642.     begin
  643.       Down := not Down;
  644.       DrawButton(CurrentButton, CurrentRect.Left);
  645.     end;
  646.   end;
  647. end;
  648.  
  649. procedure TMediaPlayer.DoClick(Button: TMPBtnType);
  650. var
  651.   DoDefault: Boolean;
  652. begin
  653.   DoDefault := True;
  654.   Click(CurrentButton, DoDefault);
  655.   if DoDefault then
  656.   begin
  657.     case CurrentButton of
  658.       btPlay: Play;
  659.       btPause: Pause;
  660.       btStop: Stop;
  661.       btNext: Next;
  662.       btPrev: Previous;
  663.       btStep: Step;
  664.       btBack: Back;
  665.       btRecord: StartRecording;
  666.       btEject: Eject;
  667.     end;
  668.     DoPostClick(CurrentButton);
  669.   end;
  670. end;
  671.  
  672. procedure TMediaPlayer.DoPostClick(Button: TMPBtnType);
  673. begin
  674.   PostClick(CurrentButton);
  675. end;
  676.  
  677. procedure TMediaPlayer.WMLButtonUp(var Message: TWMLButtonUp);
  678. begin
  679.   MouseCapture := False;
  680.   if Pressed and Down then
  681.   begin
  682.     Down := False;
  683.     DrawButton(CurrentButton, CurrentRect.Left);  {raise button before calling code}
  684.     DoClick(CurrentButton);
  685.     if FAutoEnable and (FError = 0) and MCIOpened then
  686.     begin
  687.       AutoButtonSet(CurrentButton);
  688.       DrawAutoButtons;
  689.     end;
  690.   end;
  691.   Pressed := False;
  692. end;
  693.  
  694. procedure TMediaPlayer.WMSetFocus(var Message: TWMSetFocus);
  695. begin
  696.   Paint;
  697. end;
  698.  
  699. procedure TMediaPlayer.WMKillFocus(var Message: TWMKillFocus);
  700. begin
  701.   Paint;
  702. end;
  703.  
  704. procedure TMediaPlayer.WMGetDlgCode(var Message: TWMGetDlgCode);
  705. begin
  706.   Message.Result := DLGC_WANTARROWS;
  707. end;
  708.  
  709. procedure TMediaPlayer.KeyDown(var Key: Word; Shift: TShiftState);
  710. var
  711.   NewFocus: TMPBtnType;
  712. begin
  713.   case Key of
  714.     VK_RIGHT:
  715.       begin
  716.         NewFocus := FocusedButton;
  717.         repeat
  718.           if NewFocus < High(Buttons) then
  719.             NewFocus := Succ(NewFocus);
  720.         until (NewFocus = High(Buttons)) or (Buttons[NewFocus].Visible);
  721.         if NewFocus <> FocusedButton then
  722.         begin
  723.           FocusedButton := NewFocus;
  724.           Invalidate;
  725.         end;
  726.       end;
  727.     VK_LEFT:
  728.       begin
  729.         NewFocus := FocusedButton;
  730.         repeat
  731.           if NewFocus > Low(Buttons) then
  732.             NewFocus := Pred(NewFocus);
  733.         until (NewFocus = Low(Buttons)) or (Buttons[NewFocus].Visible);
  734.         if NewFocus <> FocusedButton then
  735.         begin
  736.           FocusedButton := NewFocus;
  737.           Invalidate;
  738.         end;
  739.       end;
  740.     VK_SPACE:
  741.       begin
  742.         if Buttons[FocusedButton].Enabled then
  743.         begin
  744.           CurrentButton := FocusedButton;
  745.           DoClick(CurrentButton);
  746.           if FAutoEnable then
  747.           begin
  748.             AutoButtonSet(CurrentButton);
  749.             DrawAutoButtons;
  750.           end;
  751.         end;
  752.       end;
  753.   end;
  754. end;
  755.  
  756. {MCI message generated when Notify=True, and MCI command completes}
  757. procedure TMediaPlayer.MMNotify(var Message: TMessage);
  758. begin
  759.   if FAutoEnable and (Mode = mpStopped) then
  760.   begin {special AutoEnable case for when Play and Record finish}
  761.     if FCanPlay then Include(FAutoButtons,btPlay);
  762.     if FCanRecord then Include(FAutoButtons,btRecord);
  763.     FAutoButtons := FAutoButtons - [btStop,btPause];
  764.     DrawAutoButtons;
  765.   end;
  766.   case Message.WParam of
  767.     mci_Notify_Successful: FNotifyValue := nvSuccessful;
  768.     mci_Notify_Superseded: FNotifyValue := nvSuperseded;
  769.     mci_Notify_Aborted: FNotifyValue := nvAborted;
  770.     mci_Notify_Failure: FNotifyValue := nvFailure;
  771.   end;
  772.   DoNotify;
  773. end;
  774.  
  775. {for MCI Commands to make sure device is open, else raise exception}
  776. procedure TMediaPlayer.CheckIfOpen;
  777. begin
  778.   if not MCIOpened then raise EMCIDeviceError.Create(sNotOpenErr);
  779. end;
  780.  
  781. procedure TMediaPlayer.Click(Button: TMPBtnType; var DoDefault: Boolean);
  782. begin
  783.   if Assigned(FOnCLick) then FOnClick(Self, Button, DoDefault);
  784. end;
  785.  
  786. procedure TMediaPlayer.PostClick(Button: TMPBtnType);
  787. begin
  788.   if Assigned(FOnPostCLick) then FOnPostClick(Self, Button);
  789. end;
  790.  
  791. procedure TMediaPlayer.DoNotify;
  792. begin
  793.   if Assigned(FOnNotify) then FOnNotify(Self);
  794. end;
  795.  
  796. procedure TMediaPlayer.Updated;
  797. begin
  798.   inherited;
  799.   Adjust;
  800. end;
  801.  
  802. {***** MCI Commands *****}
  803.  
  804. procedure TMediaPlayer.Open;
  805. const
  806.   DeviceName: array[TMPDeviceTypes] of PChar = ('', 'AVIVideo', 'CDAudio', 'DAT',
  807.     'DigitalVideo', 'MMMovie', 'Other', 'Overlay', 'Scanner', 'Sequencer',
  808.     'VCR', 'Videodisc', 'WaveAudio');
  809. var
  810.   OpenParm: TMCI_Open_Parms;
  811.   DisplayR: TRect;
  812. begin
  813.   if MCIOpened then Close; {must close MCI Device first before opening another}
  814.  
  815.   OpenParm.dwCallback := 0;
  816.   if FDeviceType <> dtAutoSelect then {fill in Device Type}
  817.    OpenParm.lpstrDeviceType := DeviceName[FDeviceType];
  818.   if FElementName <> '' then
  819.     OpenParm.lpstrElementName := PChar(FElementName);
  820.  
  821.   FFlags := 0;
  822.   if FUseWait then
  823.   begin
  824.     if FWait then FFlags := mci_Wait;
  825.     FUseWait := False;
  826.   end
  827.   else FFlags := mci_Wait;
  828.   if FUseNotify then
  829.   begin
  830.     if FNotify then FFlags := FFlags or mci_Notify;
  831.     FUseNotify := False;
  832.   end;
  833.   if FElementName <> '' then FFlags := FFlags or mci_Open_Element;
  834.   if FDeviceType <> dtAutoSelect then FFlags := FFlags or mci_Open_Type;
  835.   if FShareable then FFlags := FFlags or mci_Open_Shareable;
  836.   OpenParm.dwCallback := Handle;
  837.   FError := mciSendCommand(0, mci_Open, FFlags, Longint(@OpenParm));
  838.  
  839.   if FError <> 0 then {problem opening device}
  840.     raise EMCIDeviceError.Create(ErrorMessage)
  841.   else {device successfully opened}
  842.   begin
  843.     MCIOpened := True;
  844.     FDeviceID := OpenParm.wDeviceID;
  845.     FFrames := Length div 10;  {default frames to step = 10% of total frames}
  846.     GetDeviceCaps; {must first get device capabilities}
  847.     if FHasVideo then {used for video output positioning}
  848.     begin
  849.       Display := FDisplay; {if one was set in design mode}
  850.       DisplayR := GetDisplayRect;
  851.       FDWidth := DisplayR.Right-DisplayR.Left;
  852.       FDHeight := DisplayR.Bottom-DisplayR.Top;
  853.     end;
  854.     if (FDeviceType = dtCDAudio) or (FDeviceType = dtVideodisc) then
  855.       TimeFormat := tfTMSF; {set timeformat to use tracks}
  856.     
  857.     FAutoButtons := [btNext,btPrev]; {assumed all devices can seek to start, end}
  858.     if FCanStep then FAutoButtons := FAutoButtons + [btStep,btBack];
  859.     if FCanPlay then Include(FAutoButtons, btPlay);
  860.     if FCanRecord then Include(FAutoButtons, btRecord);
  861.     if FCanEject then Include(FAutoButtons, btEject);
  862.     if Mode = mpPlaying then AutoButtonSet(btPlay); {e.g. CD device}
  863.     DrawAutoButtons;
  864.   end;
  865.     
  866. end;
  867.  
  868. procedure TMediaPlayer.Close;
  869. var
  870.   GenParm: TMCI_Generic_Parms;
  871. begin
  872.   if FDeviceID <> 0 then
  873.   begin
  874.     FFlags := 0;
  875.     if FUseWait then
  876.     begin
  877.       if FWait then FFlags := mci_Wait;
  878.       FUseWait := False;
  879.     end
  880.     else FFlags := mci_Wait;
  881.     if FUseNotify then
  882.     begin
  883.       if FNotify then FFlags := FFlags or mci_Notify;
  884.       FUseNotify := False;
  885.     end;
  886.     GenParm.dwCallback := Handle;
  887.     FError := mciSendCommand( FDeviceID, mci_Close, FFlags, Longint(@GenParm));
  888.     if FError = 0 then
  889.     begin
  890.       MCIOpened := False;
  891.       FDeviceID := 0;
  892.       FAutoButtons := [];
  893.       DrawAutoButtons;
  894.     end;
  895.   end; {if DeviceID <> 0}
  896. end;
  897.  
  898. procedure TMediaPlayer.Play;
  899. var
  900.   PlayParm: TMCI_Play_Parms;
  901. begin
  902.   CheckIfOpen; {raises exception if device is not open}
  903.  
  904.   {if at the end of media, and not using StartPos or EndPos - go to start}
  905.   if FAutoRewind and (Position = Length) then
  906.     if not FUseFrom and not FUseTo then Rewind;
  907.  
  908.   FFlags := 0;
  909.   if FUseNotify then
  910.   begin
  911.     if FNotify then FFlags := mci_Notify;
  912.     FUseNotify := False;
  913.   end else FFlags := mci_Notify;
  914.   if FUseWait then
  915.   begin
  916.     if FWait then FFlags := FFlags or mci_Wait;
  917.     FUseWait := False;
  918.   end;
  919.   if FUseFrom then
  920.   begin
  921.     FFlags := FFlags or mci_From;
  922.     PlayParm.dwFrom := FFrom;
  923.     FUseFrom := False; {only applies to this mciSendCommand}
  924.   end;
  925.   if FUseTo then
  926.   begin
  927.     FFlags := FFlags or mci_To;
  928.     PlayParm.dwTo := FTo;
  929.     FUseTo := False; {only applies to this mciSendCommand}
  930.   end;
  931.   PlayParm.dwCallback := Handle;
  932.   FError := mciSendCommand( FDeviceID, mci_Play, FFlags, Longint(@PlayParm));
  933. end;
  934.  
  935. procedure TMediaPlayer.StartRecording;
  936. var
  937.   RecordParm: TMCI_Record_Parms;
  938. begin
  939.   CheckIfOpen; {raises exception if device is not open}
  940.  
  941.   FFlags := 0;
  942.   if FUseNotify then
  943.   begin
  944.     if FNotify then FFlags := mci_Notify;
  945.     FUseNotify := False;
  946.   end
  947.   else FFlags := mci_Notify;
  948.   if FUseWait then
  949.   begin
  950.     if FWait then FFlags := FFlags or mci_Wait;
  951.     FUseWait := False;
  952.   end;
  953.  
  954.   if FUseFrom then
  955.   begin
  956.     FFlags := FFlags or mci_From;
  957.     RecordParm.dwFrom := FFrom;
  958.     FUseFrom := False;
  959.   end;
  960.   if FUseTo then
  961.   begin
  962.     FFlags := FFlags or mci_To;
  963.     RecordParm.dwTo := FTo;
  964.     FUseTo := False;
  965.   end;
  966.   RecordParm.dwCallback := Handle;
  967.   FError := mciSendCommand( FDeviceID, mci_Record, FFlags, Longint(@RecordParm));
  968. end;
  969.  
  970. procedure TMediaPlayer.Stop;
  971. var
  972.   GenParm: TMCI_Generic_Parms;
  973. begin
  974.   CheckIfOpen; {raises exception if device is not open}
  975.  
  976.   FFlags := 0;
  977.   if FUseWait then
  978.   begin
  979.     if FWait then FFlags := mci_Wait;
  980.     FUseWait := False;
  981.   end
  982.   else FFlags := mci_Wait;
  983.   if FUseNotify then
  984.   begin
  985.     if FNotify then FFlags := FFlags or mci_Notify;
  986.     FUseNotify := False;
  987.   end;
  988.   GenParm.dwCallback := Handle;
  989.   FError := mciSendCommand( FDeviceID, mci_Stop, FFlags, Longint(@GenParm));
  990. end;
  991.  
  992. procedure TMediaPlayer.Pause;
  993. begin
  994.   if not MCIOpened then Raise EMCIDeviceError.Create(sNotOpenErr);
  995.   if Mode = mpPlaying then PauseOnly
  996.   else
  997.    if Mode = mpPaused then Resume;
  998. end;
  999.  
  1000. procedure TMediaPlayer.PauseOnly;
  1001. var
  1002.   GenParm: TMCI_Generic_Parms;
  1003. begin
  1004.   CheckIfOpen; {raises exception if device is not open}
  1005.  
  1006.   FFlags := 0;
  1007.   if FUseWait then
  1008.   begin
  1009.     if FWait then FFlags := mci_Wait;
  1010.     FUseWait := False;
  1011.   end
  1012.   else FFlags := mci_Wait;
  1013.   if FUseNotify then
  1014.   begin
  1015.     if FNotify then FFlags := FFlags or mci_Notify;
  1016.     FUseNotify := False;
  1017.   end;
  1018.   GenParm.dwCallback := Handle;
  1019.   FError := mciSendCommand( FDeviceID, mci_Pause, FFlags, Longint(@GenParm));
  1020. end;
  1021.  
  1022. procedure TMediaPlayer.Resume;
  1023. var
  1024.   GenParm: TMCI_Generic_Parms;
  1025. begin
  1026.   CheckIfOpen; {raises exception if device is not open}
  1027.  
  1028.   FFlags := 0;
  1029.   if FUseNotify then
  1030.   begin
  1031.     if FNotify then FFlags := mci_Notify;
  1032.   end
  1033.   else FFlags := mci_Notify;
  1034.   if FUseWait then
  1035.   begin
  1036.     if FWait then FFlags := FFlags or mci_Wait;
  1037.   end;
  1038.   GenParm.dwCallback := Handle;
  1039.   FError := mciSendCommand( FDeviceID, mci_Resume, FFlags, Longint(@GenParm));
  1040.   
  1041.   {if error calling resume (resume not supported),  call Play}
  1042.   if FError <> 0 then
  1043.     Play {FUseNotify & FUseWait reset by Play}
  1044.   else
  1045.   begin
  1046.     if FUseNotify then
  1047.       FUseNotify := False;
  1048.     if FUseWait then
  1049.       FUseWait := False;
  1050.   end;
  1051. end;
  1052.  
  1053. procedure TMediaPlayer.Next;
  1054. var
  1055.   SeekParm: TMCI_Seek_Parms;
  1056.   TempFlags: Longint;
  1057. begin
  1058.   CheckIfOpen; {raises exception if device is not open}
  1059.  
  1060.   FFlags := 0;
  1061.   if FUseWait then
  1062.   begin
  1063.     if FWait then FFlags := mci_Wait;
  1064.     FUseWait := False;
  1065.   end
  1066.   else FFlags := mci_Wait;
  1067.   if FUseNotify then
  1068.   begin
  1069.     if FNotify then FFlags := FFlags or mci_Notify;
  1070.     FUseNotify := False;
  1071.   end;
  1072.  
  1073.   TempFlags := FFlags; {preserve FFlags from GetTimeFormat & GetPosition}
  1074.   if TimeFormat = tfTMSF then {using Tracks}
  1075.   begin
  1076.     if Mode = mpPlaying then 
  1077.     begin
  1078.       if mci_TMSF_Track(Position) = Tracks then {if at last track}
  1079.          StartPos := GetTrackPosition(Tracks) {go to beg of last}
  1080.       else {go to next track}
  1081.          StartPos := GetTrackPosition((mci_TMSF_Track(Position))+1);
  1082.       Play;
  1083.       CurrentButton := btPlay;
  1084.       Exit;
  1085.     end
  1086.     else
  1087.     begin
  1088.       if mci_TMSF_Track(Position) = Tracks then {if at last track}
  1089.          SeekParm.dwTo := GetTrackPosition(Tracks) {go to beg of last}
  1090.       else {go to next track}
  1091.          SeekParm.dwTo := GetTrackPosition((mci_TMSF_Track(Position))+1);
  1092.       FFlags := TempFlags or mci_To;
  1093.     end;
  1094.   end
  1095.   else
  1096.     FFlags := TempFlags or mci_Seek_To_End;
  1097.     
  1098.   SeekParm.dwCallback := Handle;
  1099.   FError := mciSendCommand( FDeviceID, mci_Seek, FFlags, Longint(@SeekParm));
  1100. end; {Next}
  1101.  
  1102.  
  1103. procedure TMediaPlayer.Previous;
  1104. var
  1105.   SeekParm: TMCI_Seek_Parms;
  1106.   tpos,cpos,TempFlags: Longint;
  1107. begin
  1108.   CheckIfOpen; {raises exception if device is not open}
  1109.  
  1110.   FFlags := 0;
  1111.   if FUseWait then
  1112.   begin
  1113.     if FWait then FFlags := mci_Wait;
  1114.     FUseWait := False;
  1115.   end
  1116.   else FFlags := mci_Wait;
  1117.   if FUseNotify then
  1118.   begin
  1119.     if FNotify then FFlags := FFlags or mci_Notify;
  1120.     FUseNotify := False;
  1121.   end;
  1122.   
  1123.   TempFlags := FFlags; {preserve FFlags from GetTimeFormat & GetPosition}
  1124.   if TimeFormat = tfTMSF then {using Tracks}
  1125.   begin
  1126.     cpos := Position;
  1127.     tpos := GetTrackPosition(mci_TMSF_Track(Position));
  1128.     if Mode = mpPlaying then 
  1129.     begin
  1130.         {if not on first track, and at beginning of current track}
  1131.         if (mci_TMSF_Track(cpos) <> 1) and
  1132.           (mci_TMSF_Minute(cpos) = mci_TMSF_Minute(tpos)) and
  1133.           (mci_TMSF_Second(cpos) = mci_TMSF_Second(tpos)) then
  1134.           StartPos := GetTrackPosition(mci_TMSF_Track(Position)-1) {go to previous}
  1135.         else
  1136.           StartPos := tpos; {otherwise, go to beginning of current}
  1137.       Play;
  1138.       CurrentButton := btPlay;
  1139.       Exit;
  1140.      end
  1141.      else
  1142.      begin
  1143.         {if not on first track, and at beginning of current track}
  1144.         if (mci_TMSF_Track(cpos) <> 1) and
  1145.           (mci_TMSF_Minute(cpos) = mci_TMSF_Minute(tpos)) and
  1146.           (mci_TMSF_Second(cpos) = mci_TMSF_Second(tpos)) then
  1147.           SeekParm.dwTo := GetTrackPosition(mci_TMSF_Track(Position)-1) {go to previous}
  1148.         else
  1149.           SeekParm.dwTo := tpos; {otherwise, go to beginning of current}
  1150.         FFlags := TempFlags or mci_To;
  1151.      end;
  1152.   end
  1153.   else
  1154.     FFlags := TempFlags or mci_Seek_To_Start;
  1155.     
  1156.   SeekParm.dwCallback := Handle;
  1157.   FError := mciSendCommand( FDeviceID, mci_Seek, FFlags, Longint(@SeekParm));
  1158. end; {Previous}
  1159.  
  1160. procedure TMediaPlayer.Step;
  1161. var
  1162.   AStepParm: TMCI_Anim_Step_Parms;
  1163. begin
  1164.   CheckIfOpen; {raises exception if device is not open}
  1165.  
  1166.   if FHasVideo then
  1167.   begin
  1168.     if FAutoRewind and (Position = Length) then Rewind;
  1169.  
  1170.     FFlags := 0;
  1171.     if FUseWait then
  1172.     begin
  1173.       if FWait then FFlags := mci_Wait;
  1174.       FUseWait := False;
  1175.     end
  1176.     else FFlags := mci_Wait;
  1177.     if FUseNotify then
  1178.     begin
  1179.       if FNotify then FFlags := FFlags or mci_Notify;
  1180.       FUseNotify := False;
  1181.     end;
  1182.     FFlags := FFlags or mci_Anim_Step_Frames;
  1183.     AStepParm.dwFrames := FFrames;
  1184.     AStepParm.dwCallback := Handle;
  1185.     FError := mciSendCommand( FDeviceID, mci_Step, FFlags, Longint(@AStepParm) );
  1186.   end; {if HasVideo}
  1187. end;
  1188.  
  1189. procedure TMediaPlayer.Back;
  1190. var
  1191.   AStepParm: TMCI_Anim_Step_Parms;
  1192. begin
  1193.   CheckIfOpen; {raises exception if device is not open}
  1194.  
  1195.   if FHasVideo then
  1196.   begin
  1197.     FFlags := 0;
  1198.     if FUseWait then
  1199.     begin
  1200.       if FWait then FFlags := mci_Wait;
  1201.       FUseWait := False;
  1202.     end
  1203.     else FFlags := mci_Wait;
  1204.     if FUseNotify then
  1205.     begin
  1206.       if FNotify then FFlags := FFlags or mci_Notify;
  1207.       FUseNotify := False;
  1208.     end;
  1209.     FFlags := FFlags or mci_Anim_Step_Frames or mci_Anim_Step_Reverse;
  1210.     AStepParm.dwFrames := FFrames;
  1211.     AStepParm.dwCallback := Handle;
  1212.     FError := mciSendCommand( FDeviceID, mci_Step, FFlags, Longint(@AStepParm) );
  1213.   end; {if HasVideo}
  1214. end; {Back}
  1215.  
  1216. procedure TMediaPlayer.Eject;
  1217. var
  1218.   SetParm: TMCI_Set_Parms;
  1219. begin
  1220.   CheckIfOpen; {raises exception if device is not open}
  1221.  
  1222.   if FCanEject then
  1223.   begin
  1224.     FFlags := 0;
  1225.     if FUseWait then
  1226.     begin
  1227.       if FWait then FFlags := mci_Wait;
  1228.       FUseWait := False;
  1229.     end
  1230.     else FFlags := mci_Wait;
  1231.     if FUseNotify then
  1232.     begin
  1233.       if FNotify then FFlags := FFlags or mci_Notify;
  1234.       FUseNotify := False;
  1235.     end;
  1236.     FFlags := FFlags or mci_Set_Door_Open;
  1237.     SetParm.dwCallback := Handle;
  1238.     FError := mciSendCommand( FDeviceID, mci_Set, FFlags, Longint(@SetParm) );
  1239.   end; {if CanEject}
  1240. end; {Eject}
  1241.  
  1242. procedure TMediaPlayer.SetPosition(Value: Longint);
  1243. var
  1244.   SeekParm: TMCI_Seek_Parms;
  1245. begin
  1246.   CheckIfOpen; {raises exception if device is not open}
  1247.  
  1248.   FFlags := 0;
  1249.   if FUseWait then
  1250.   begin
  1251.     if FWait then FFlags := mci_Wait;
  1252.     FUseWait := False;
  1253.   end
  1254.   else FFlags := mci_Wait;
  1255.   if FUseNotify then
  1256.   begin
  1257.     if FNotify then FFlags := FFlags or mci_Notify;
  1258.     FUseNotify := False;
  1259.   end;
  1260.   FFlags := FFlags or mci_To;
  1261.   SeekParm.dwCallback := Handle;
  1262.   SeekParm.dwTo := Value;
  1263.   FError := mciSendCommand( FDeviceID, mci_Seek, FFlags, Longint(@SeekParm));
  1264. end;
  1265.  
  1266. procedure TMediaPlayer.Rewind;
  1267. var
  1268.   SeekParm: TMCI_Seek_Parms;
  1269.   RFlags: Longint;
  1270. begin
  1271.   CheckIfOpen; {raises exception if device is not open}
  1272.   RFlags := mci_Wait or mci_Seek_To_Start;
  1273.   mciSendCommand( FDeviceID, mci_Seek, RFlags, Longint(@SeekParm));
  1274. end;
  1275.  
  1276. function TMediaPlayer.GetTrackLength(TrackNum: Integer): Longint;
  1277. var
  1278.   StatusParm: TMCI_Status_Parms;
  1279. begin
  1280.   CheckIfOpen; {raises exception if device is not open}
  1281.   FFlags := mci_Wait or mci_Status_Item or mci_Track;
  1282.   StatusParm.dwItem := mci_Status_Length;
  1283.   StatusParm.dwTrack := Longint(TrackNum);
  1284.   mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1285.   Result := StatusParm.dwReturn;
  1286. end;
  1287.  
  1288. function TMediaPlayer.GetTrackPosition(TrackNum: Integer): Longint;
  1289. var
  1290.   StatusParm: TMCI_Status_Parms;
  1291. begin
  1292.   FFlags := mci_Wait or mci_Status_Item or mci_Track;
  1293.   StatusParm.dwItem := mci_Status_Position;
  1294.   StatusParm.dwTrack := Longint(TrackNum);
  1295.   mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1296.   Result := StatusParm.dwReturn;
  1297. end;
  1298.  
  1299. procedure TMediaPlayer.Save;
  1300. var
  1301.   SaveParm: TMCI_SaveParms;
  1302. begin
  1303.   CheckIfOpen; {raises exception if device is not open}
  1304.   if FElementName <> '' then {make sure a file has been specified to save to}
  1305.   begin
  1306.     SaveParm.lpfilename := PChar(FElementName);
  1307.  
  1308.     FFlags := 0;
  1309.     if FUseWait then
  1310.     begin
  1311.       if FWait then FFlags := mci_Wait;
  1312.       FUseWait := False;
  1313.     end
  1314.     else FFlags := mci_Wait;
  1315.     if FUseNotify then
  1316.     begin
  1317.       if FNotify then FFlags := FFlags or mci_Notify;
  1318.       FUseNotify := False;
  1319.     end;
  1320.     SaveParm.dwCallback := Handle;
  1321.     FFlags := FFlags or mci_Save_File;
  1322.     FError := mciSendCommand(FDeviceID, mci_Save, FFlags, Longint(@SaveParm));
  1323.     end;
  1324. end;
  1325.  
  1326.  
  1327. {*** procedures that set control flags for MCI Commands ***}
  1328. procedure TMediaPlayer.SetWait( Flag: Boolean );
  1329. begin
  1330.   if Flag <> FWait then FWait := Flag;
  1331.   FUseWait := True;
  1332. end;
  1333.  
  1334. procedure TMediaPlayer.SetNotify( Flag: Boolean );
  1335. begin
  1336.   if Flag <> FNotify then FNotify := Flag;
  1337.   FUseNotify := True;
  1338. end;
  1339.  
  1340. procedure TMediaPlayer.SetFrom( Value: Longint );
  1341. begin
  1342.   if Value <> FFrom then FFrom := Value;
  1343.   FUseFrom := True;
  1344. end;
  1345.  
  1346. procedure TMediaPlayer.SetTo( Value: Longint );
  1347. begin
  1348.   if Value <> FTo then FTo := Value;
  1349.   FUseTo := True;
  1350. end;
  1351.  
  1352.  
  1353. procedure TMediaPlayer.SetDeviceType( Value: TMPDeviceTypes );
  1354. begin
  1355.   if Value <> FDeviceType then FDeviceType := Value;
  1356. end;
  1357.  
  1358. procedure TMediaPlayer.SetTimeFormat( Value: TMPTimeFormats );
  1359. var
  1360.   SetParm: TMCI_Set_Parms;
  1361. begin
  1362.   begin
  1363.     FFlags := mci_Notify or mci_Set_Time_Format;
  1364.     SetParm.dwTimeFormat := Longint(Value);
  1365.     FError := mciSendCommand( FDeviceID, mci_Set, FFlags, Longint(@SetParm) );
  1366.   end;
  1367. end;
  1368.  
  1369. {setting a TWinControl to display video devices' output}
  1370. procedure TMediaPlayer.SetDisplay( Value: TWinControl );
  1371. var
  1372.   AWindowParm: TMCI_Anim_Window_Parms;
  1373. begin
  1374.   if (Value <> nil) and MCIOpened and FHasVideo then
  1375.   begin
  1376.     FFlags := mci_Wait or mci_Anim_Window_hWnd;
  1377.     AWindowParm.Wnd := Longint(Value.Handle);
  1378.     FError := mciSendCommand( FDeviceID, mci_Window, FFlags, Longint(@AWindowParm) );
  1379.     if FError <> 0 then
  1380.       FDisplay := nil {alternate window not supported}
  1381.     else
  1382.     begin
  1383.       FDisplay := Value; {alternate window supported}
  1384.       Value.FreeNotification(Self);
  1385.     end;
  1386.   end
  1387.   else FDisplay := Value;
  1388. end;
  1389.  
  1390. procedure TMediaPlayer.Notification(AComponent: TComponent;
  1391.   Operation: TOperation);
  1392. begin
  1393.   inherited Notification(AComponent, Operation);
  1394.   if (Operation = opRemove) and (AComponent = FDisplay) then
  1395.   begin
  1396.     if MCIOpened then SetOrigDisplay;
  1397.     FDisplay := nil;
  1398.   end;
  1399. end;
  1400.  
  1401. { special case to set video display back to original window,
  1402.   when FDisplay's TWinControl is deleted at runtime }
  1403. procedure TMediaPlayer.SetOrigDisplay;
  1404. var
  1405.   AWindowParm: TMCI_Anim_Window_Parms;
  1406. begin
  1407.   if MCIOpened and FHasVideo then
  1408.   begin
  1409.     FFlags := mci_Wait or mci_Anim_Window_hWnd;
  1410.     AWindowParm.Wnd := mci_Anim_Window_Default;
  1411.     FError := mciSendCommand( FDeviceID, mci_Window, FFlags, Longint(@AWindowParm) );
  1412.   end;
  1413. end;
  1414.  
  1415. {setting a rect for user-defined form to display video devices' output}
  1416. procedure TMediaPlayer.SetDisplayRect( Value: TRect );
  1417. var
  1418.   RectParms: TMCI_Anim_Rect_Parms;
  1419.   WorkR: TRect;
  1420. begin
  1421.   if MCIOpened and FHasVideo then
  1422.   begin
  1423.     {special case, use default width and height}
  1424.     if (Value.Bottom = 0) and (Value.Right = 0) then
  1425.     begin
  1426.       with Value do
  1427.         WorkR := Rect(Left, Top, FDWidth, FDHeight);
  1428.     end
  1429.     else WorkR := Value;
  1430.     FFlags := mci_Anim_RECT or mci_Anim_Put_Destination;
  1431.     RectParms.rc := WorkR;
  1432.     FError := mciSendCommand( FDeviceID, mci_Put, FFlags, Longint(@RectParms) );
  1433.   end;
  1434. end;
  1435.  
  1436.  
  1437. {***** functions to get device capabilities and status ***}
  1438.  
  1439. function TMediaPlayer.GetDisplayRect: TRect;
  1440. var
  1441.   RectParms: TMCI_Anim_Rect_Parms;
  1442. begin
  1443.   if MCIOpened and FHasVideo then
  1444.   begin
  1445.     FFlags := mci_Anim_Where_Destination;
  1446.     FError := mciSendCommand( FDeviceID, mci_Where, FFlags, Longint(@RectParms) );
  1447.     Result := RectParms.rc;
  1448.   end;
  1449. end;
  1450.  
  1451. { fills in static properties upon opening MCI Device }
  1452. procedure TMediaPlayer.GetDeviceCaps;
  1453. var
  1454.   DevCapParm: TMCI_GetDevCaps_Parms;
  1455.   devType: Longint;
  1456.   RectParms: TMCI_Anim_Rect_Parms;
  1457.   WorkR: TRect;
  1458. begin
  1459.   FFlags := mci_Wait or mci_GetDevCaps_Item;
  1460.  
  1461.   DevCapParm.dwItem := mci_GetDevCaps_Can_Play;
  1462.   mciSendCommand(FDeviceID, mci_GetDevCaps, FFlags,  Longint(@DevCapParm) );
  1463.   FCanPlay := Boolean(DevCapParm.dwReturn);
  1464.   if FCanPlay then Include(FCapabilities, mpCanPlay);
  1465.  
  1466.   DevCapParm.dwItem := mci_GetDevCaps_Can_Record;
  1467.   mciSendCommand(FDeviceID, mci_GetDevCaps, FFlags,  Longint(@DevCapParm) );
  1468.   FCanRecord := Boolean(DevCapParm.dwReturn);
  1469.   if FCanRecord then Include(FCapabilities, mpCanRecord);
  1470.  
  1471.   DevCapParm.dwItem := mci_GetDevCaps_Can_Eject;
  1472.   mciSendCommand(FDeviceID, mci_GetDevCaps, FFlags,  Longint(@DevCapParm) );
  1473.   FCanEject := Boolean(DevCapParm.dwReturn);
  1474.   if FCanEject then Include(FCapabilities, mpCanEject);
  1475.  
  1476.   DevCapParm.dwItem := mci_GetDevCaps_Has_Video;
  1477.   mciSendCommand(FDeviceID, mci_GetDevCaps, FFlags,  Longint(@DevCapParm) );
  1478.   FHasVideo := Boolean(DevCapParm.dwReturn);
  1479.   if FHasVideo then Include(FCapabilities, mpUsesWindow);
  1480.  
  1481.   DevCapParm.dwItem := mci_GetDevCaps_Device_Type;
  1482.   mciSendCommand(FDeviceID, mci_GetDevCaps, FFlags,  Longint(@DevCapParm) );
  1483.   devType := DevCapParm.dwReturn;
  1484.   if (devType = mci_DevType_Animation) or
  1485.      (devType = mci_DevType_Digital_Video) or
  1486.      (devType = mci_DevType_Overlay) or
  1487.      (devType = mci_DevType_VCR) then FCanStep := True;
  1488.   if FCanStep then Include(FCapabilities, mpCanStep);
  1489.  
  1490.   FFlags := mci_Anim_Where_Source;
  1491.   FError := mciSendCommand( FDeviceID, mci_Where, FFlags, Longint(@RectParms) );
  1492.   WorkR := RectParms.rc;
  1493.   FDWidth := WorkR.Right - WorkR.Left;
  1494.   FDHeight := WorkR.Bottom - WorkR.Top;
  1495. end; {GetDeviceCaps}
  1496.  
  1497. function TMediaPlayer.GetStart: Longint;
  1498. var
  1499.   StatusParm: TMCI_Status_Parms;
  1500. begin
  1501.   CheckIfOpen; {raises exception if device is not open}
  1502.   FFlags := mci_Wait or mci_Status_Item or mci_Status_Start;
  1503.   StatusParm.dwItem := mci_Status_Position;
  1504.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1505.   Result := StatusParm.dwReturn;
  1506. end;
  1507.  
  1508. function TMediaPlayer.GetLength: Longint;
  1509. var
  1510.   StatusParm: TMCI_Status_Parms;
  1511. begin
  1512.   CheckIfOpen; {raises exception if device is not open}
  1513.   FFlags := mci_Wait or mci_Status_Item;
  1514.   StatusParm.dwItem := mci_Status_Length;
  1515.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1516.   Result := StatusParm.dwReturn;
  1517. end;
  1518.  
  1519. function TMediaPlayer.GetTracks: Longint;
  1520. var
  1521.   StatusParm: TMCI_Status_Parms;
  1522. begin
  1523.   CheckIfOpen; {raises exception if device is not open}
  1524.   FFlags := mci_Wait or mci_Status_Item;
  1525.   StatusParm.dwItem := mci_Status_Number_Of_Tracks;
  1526.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1527.   Result := StatusParm.dwReturn;
  1528. end;
  1529.  
  1530. function TMediaPlayer.GetMode: TMPModes;
  1531. var
  1532.   StatusParm: TMCI_Status_Parms;
  1533. begin
  1534.   FFlags := mci_Wait or mci_Status_Item;
  1535.   StatusParm.dwItem := mci_Status_Mode;
  1536.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1537.   Result := TMPModes(StatusParm.dwReturn - 524); {MCI Mode #s are 524+enum}
  1538. end;
  1539.  
  1540. function TMediaPlayer.GetPosition: Longint;
  1541. var
  1542.   StatusParm: TMCI_Status_Parms;
  1543. begin
  1544.   FFlags := mci_Wait or mci_Status_Item;
  1545.   StatusParm.dwItem := mci_Status_Position;
  1546.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1547.   Result := StatusParm.dwReturn;
  1548. end;
  1549.  
  1550. function TMediaPlayer.GetTimeFormat: TMPTimeFormats;
  1551. var
  1552.   StatusParm: TMCI_Status_Parms;
  1553. begin
  1554.   CheckIfOpen; {raises exception if device is not open}
  1555.   FFlags := mci_Wait or mci_Status_Item;
  1556.   StatusParm.dwItem := mci_Status_Time_Format;
  1557.   FError := mciSendCommand( FDeviceID, mci_Status, FFlags, Longint(@StatusParm));
  1558.   Result := TMPTimeFormats(StatusParm.dwReturn);
  1559. end;
  1560.  
  1561. function TMediaPlayer.GetErrorMessage: string;
  1562. var
  1563.   ErrMsg: array[0..4095] of Char;
  1564. begin
  1565.   if not mciGetErrorString(FError, ErrMsg, SizeOf(ErrMsg)) then
  1566.     Result := SMCIUnknownError
  1567.   else SetString(Result, ErrMsg, StrLen(ErrMsg));
  1568. end;
  1569.  
  1570. end.
  1571.